package com.zenithmind.common.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * 配置加密工具类
 * 用于加密和解密敏感配置信息
 */
@Slf4j
public class ConfigEncryptUtils {
    
    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
    private static final String ENCRYPT_PREFIX = "ENC(";
    private static final String ENCRYPT_SUFFIX = ")";
    
    // 默认密钥（生产环境应该从环境变量获取）
    private static final String DEFAULT_KEY = "ZenithMindSecretKey2024!@#$%^&*";
    
    /**
     * 生成AES密钥
     * @return Base64编码的密钥
     */
    public static String generateKey() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
            keyGenerator.init(256, new SecureRandom());
            SecretKey secretKey = keyGenerator.generateKey();
            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
        } catch (Exception e) {
            log.error("生成密钥失败", e);
            throw new RuntimeException("生成密钥失败", e);
        }
    }
    
    /**
     * 加密字符串
     * @param plainText 明文
     * @return 加密后的字符串，格式为 ENC(base64编码的密文)
     */
    public static String encrypt(String plainText) {
        return encrypt(plainText, getEncryptionKey());
    }
    
    /**
     * 加密字符串
     * @param plainText 明文
     * @param key 密钥
     * @return 加密后的字符串，格式为 ENC(base64编码的密文)
     */
    public static String encrypt(String plainText, String key) {
        if (!StringUtils.hasText(plainText)) {
            return plainText;
        }
        
        try {
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            
            byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
            
            return ENCRYPT_PREFIX + encryptedText + ENCRYPT_SUFFIX;
        } catch (Exception e) {
            log.error("加密失败: {}", plainText, e);
            throw new RuntimeException("加密失败", e);
        }
    }
    
    /**
     * 解密字符串
     * @param encryptedText 加密的字符串
     * @return 解密后的明文
     */
    public static String decrypt(String encryptedText) {
        return decrypt(encryptedText, getEncryptionKey());
    }
    
    /**
     * 解密字符串
     * @param encryptedText 加密的字符串
     * @param key 密钥
     * @return 解密后的明文
     */
    public static String decrypt(String encryptedText, String key) {
        if (!isEncrypted(encryptedText)) {
            return encryptedText; // 如果不是加密格式，直接返回
        }
        
        try {
            // 提取加密内容
            String cipherText = encryptedText.substring(
                    ENCRYPT_PREFIX.length(), 
                    encryptedText.length() - ENCRYPT_SUFFIX.length()
            );
            
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            
            byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText));
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("解密失败: {}", encryptedText, e);
            throw new RuntimeException("解密失败", e);
        }
    }
    
    /**
     * 检查字符串是否为加密格式
     * @param text 待检查的字符串
     * @return 是否为加密格式
     */
    public static boolean isEncrypted(String text) {
        return StringUtils.hasText(text) && 
               text.startsWith(ENCRYPT_PREFIX) && 
               text.endsWith(ENCRYPT_SUFFIX);
    }
    
    /**
     * 获取加密密钥
     * 优先从环境变量获取，如果没有则使用默认密钥
     * @return 加密密钥
     */
    private static String getEncryptionKey() {
        String key = System.getenv("ZENITHMIND_ENCRYPT_KEY");
        if (!StringUtils.hasText(key)) {
            key = System.getProperty("zenithmind.encrypt.key");
        }
        if (!StringUtils.hasText(key)) {
            log.warn("未设置加密密钥，使用默认密钥（生产环境不推荐）");
            key = DEFAULT_KEY;
        }
        return key;
    }
    
    /**
     * 批量处理配置值
     * 如果是加密格式则解密，否则直接返回
     * @param value 配置值
     * @return 处理后的值
     */
    public static String processConfigValue(String value) {
        if (isEncrypted(value)) {
            return decrypt(value);
        }
        return value;
    }
    
    /**
     * 主方法，用于命令行加密工具
     * 使用方法: java ConfigEncryptUtils encrypt "your-password"
     * 或者: java ConfigEncryptUtils decrypt "ENC(encrypted-text)"
     */
    public static void main(String[] args) {
        if (args.length < 2) {
            System.out.println("使用方法:");
            System.out.println("  加密: java ConfigEncryptUtils encrypt <明文>");
            System.out.println("  解密: java ConfigEncryptUtils decrypt <密文>");
            System.out.println("  生成密钥: java ConfigEncryptUtils generateKey");
            return;
        }
        
        String operation = args[0];
        
        try {
            switch (operation.toLowerCase()) {
                case "encrypt":
                    String plainText = args[1];
                    String encrypted = encrypt(plainText);
                    System.out.println("加密结果: " + encrypted);
                    break;
                    
                case "decrypt":
                    String encryptedText = args[1];
                    String decrypted = decrypt(encryptedText);
                    System.out.println("解密结果: " + decrypted);
                    break;
                    
                case "generatekey":
                    String key = generateKey();
                    System.out.println("生成的密钥: " + key);
                    break;
                    
                default:
                    System.out.println("不支持的操作: " + operation);
            }
        } catch (Exception e) {
            System.err.println("操作失败: " + e.getMessage());
        }
    }
}
